/**
 * #info
 *
 *@author   wuwg
 *@createTime   2018/03/20
 *@updateTime   2018/05/24
 *@description  scroll component  。 滚动视图组件
 */

/**
 * #item
 *
 * @type        aty-scroll
 * @cn          滚动条
 * @menu        其他
 * @stPlugin    true
 * @stContainer true
 */
import config from '../../../config/config.js'
import Emitter from '../../../mixins/emitter.js'
import { addResizeListener, removeResizeListener } from './resize-event'

//   components
import verticalScrollbar from './vertical-scrollbar/index.vue'
import horizontalScrollbar from './horizontal-scrollbar/index.vue'
// prefix
const prefixCls = config.prefix + '-scroll'
const transitionCls = config.prefix + '-scrollbar-transition'
// module
const module = {
  name: config.prefix + '-scroll',
  mixins: [Emitter],
  // components
  components: {
    verticalScrollbar,
    horizontalScrollbar
  },
  props: {
    /**
     * #property
     *
     * @name     name
     * @cn      该滚动条对应的名称
     * @type    string
     * @description 该滚动条对应的名称，页面多处用到滚动条，可以用name进行区分
     */
    name: {
      type: null
    },
    /**
     * #property
     *
     * @name     speed
     * @cn      滚动条每滚动一次内容滚动的距离
     * @type    number
     * @value   53
     * @description 滚动条每滚动一次内容滚动的距离,实际取值单位为px
     */
    speed: {
      type: Number,
      default: 53
    },
    /**
     * #property
     *
     * @name     show
     * @cn      滚动条默认是否显示
     * @type    boolean
     * @bind    must
     * @value   true
     * @description 滚动条默认是否显示
     */
    show: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name     delay
     * @cn      上拉刷新|下拉加载间隔时间
     * @type    number
     * @value    500
     * @description 上拉刷新|下拉加载间隔时间，单位毫秒，主要为了提升性能，默认为500
     */
    delay: {
      type: Number,
      default: 500
    },
    /**
     * #property
     *
     * @name     areaClass
     * @cn      按内容自增部分的class
     * @type    string
     * @bind    must
     * @description 按内容自增部分的class，即aty-scroll-area部分的class
     */
    areaClass: String
  },
  data () {
    return {
      ready: false,
      scrollY: null,
      scrollX: null,

      top: 0,
      left: 0,
      // has vertical  scroll bar
      hasVerticalScrollBar: false,
      // has horizontal  scroll bar
      hasHorizontalScrollBar: false,
      // 滚动区域的宽高
      scrollAreaWidth: null,
      scrollAreaHeight: null,

      // 滚动区域外围容器的宽高
      scrollWrapperHeight: null,
      scrollWrapperWidth: null,

      // 滚动条的位置
      verticalScrollBarPostion: 0,
      horizontalScrollBarPostion: 0,
      // 是否正在拖动
      dragging: false,
      // 开始位置（拖动内容有效）
      start: { y: 0, x: 0 },

      // 刷新
      refresh: false,
      loading: false,
      isUpdate: false,
      inited: false,
      style: { transform: 'translate(0,0)' } // 默认开启硬件加速
    }
  },
  watch: {
    top (val) {
      this.style = this.style_()
    },
    left (val) {
      this.style = this.style_()
    }
  },
  computed: {
    wrapClasses () {
      return [
        prefixCls,
        this.show ? 'show' : ''
      ]
    },
    scrollbarAreaClasses () {
      return [
        config.prefix + '-scroll-area',
        this.dragging ? '' : transitionCls,
        this.areaClass ? this.areaClass : ''
      ]
    }

  },
  methods: {
    style_ () {
      const _top = (this.top * -1) + 'px'
      const _left = (this.left * -1) + 'px'
      /**
       * #event
       *
       * @name    scroll
       * @param   _top         当前的top值
       * @param   _left        当前值的left性
       * @param   scrollBar    当前滚动条对象（this对象）
       * @body    console.log("top:"+_top+",_left:"+_left);
       * @description      滚动后触发
       */
      this.$emit('scroll', _top, _left, this)

      return {
        transform: 'translate(' + _left + ',' + _top + ')',
        msTransform: 'translate(' + _left + ',' + _top + ')',
        oTransform: 'translate(' + _left + ',' + _top + ')',
        webkitTransform: 'translate(' + _left + ',' + _top + ')',
        mozTransform: 'translate(' + _left + ',' + _top + ')'
      }
    },
    scroll (e) {
      // 如果有滚动条
      if (this.hasVerticalScrollBar || this.hasHorizontalScrollBar) {
        // 阻止默认事件
        Artery.preventDefault(e)
        this.isUpdate = false
        // 设置滚动的速度
        const num = this.speed
        // dom事件
        const shifted = e.shiftKey
        this.scrollY = e.deltaY > 0 ? num : -(num)
        this.scrollX = e.deltaX > 0 ? num : -(num)

        // 判断横向滚动的值
        if (e.deltaX == 0 && e.deltaY != 0) {
          this.scrollX = e.deltaY > 0 ? num : -(num)
        }

        // 滚动后的值
        const nextPostionY = this.top + this.scrollY
        const nextPostionX = this.left + this.scrollX

        // 判断是否可以滚动
        const canScrollY = this.scrollAreaHeight > this.scrollWrapperHeight
        const canScrollX = this.scrollAreaWidth > this.scrollWrapperWidth
        // 垂直滚动
        if (canScrollY && !shifted) {
          // 垂直移动内容
          this.verticalMoveContent(nextPostionY)
          //  移动滚动条
          this.moveTheScrollbar()
        }
        // 水平滚动
        if ((shifted && canScrollX) || !this.hasVerticalScrollBar) {
          // 水平移动内容
          this.horizontalMoveContent(nextPostionX)
          //  移动滚动条
          this.moveTheScrollbar()
        }
      }
    },

    // 开始拖动
    startDrag (e) {
      // 如果有滚动条，那么就阻止事件冒泡
      if (this.hasVerticalScrollBar || this.hasHorizontalScrollBar) {
        // 阻止默认事件，阻止事件冒泡
        Artery.stopEvent(e)
        // 正在拖动
        this.dragging = true
        // 记录拖动的开始位置
        this.start.y = e.pageY
        this.start.x = e.pageX
      }
    },
    onDrag (e) {
      // 如果存在滚动条
      if (this.dragging && (this.hasVerticalScrollBar || this.hasHorizontalScrollBar)) {
        // 阻止默认事件，阻止事件冒泡
        Artery.stopEvent(e)
        this.isUpdate = false
        e = e.changedTouches ? e.changedTouches[0] : e
        // Invers the Movement
        const yMovement = this.start.y - e.pageY
        const xMovement = this.start.x - e.pageX
        // Update the last e.page
        this.start.y = e.pageY
        this.start.x = e.pageX
        // 拖动后的值
        const nextPostionY = this.top + yMovement
        const nextPostionX = this.left + xMovement
        // 垂直移动内容
        this.verticalMoveContent(nextPostionY)
        // 水平移动内容
        this.horizontalMoveContent(nextPostionX)
        // 移动滚动条
        this.moveTheScrollbar()
      }
    },
    // 停止拖动
    stopDrag (e) {
      // 停止拖动
      this.dragging = false
    },
    // 滚动到顶部||最左侧
    scrolltoupper () {
      // 刷新
      var _this = this
      if (this.refresh || this.isUpdate) {
        return false
      }
      // 刷新
      this.refresh = setTimeout(function () {
        /**
         * #event
         *
         * @name    scrolltoupper
         * @param   _top       当前的top值
         * @param   _left      当前值的left性
         * @param   scrollBar   当前滚动条对象（this对象）
         * @body    console.log("top:"+_top+",_left:"+_left);
         * @description      上拉滚动条触顶||触左时触发
         */
        _this.$emit('scrolltoupper', _this.top, _this.left, _this)
        _this.refresh = null
      }, this.delay)
    },
    // 滚动到底部||最右侧
    scrolltolower () {
      // 加载
      var _this = this
      if (this.loading || this.isUpdate) {
        return false
      }
      // 加载
      this.loading = setTimeout(function () {
        /**
         * #event
         *
         * @name    scrolltolower
         * @param   _top       当前的top值
         * @param   _left      当前值的left性
         * @param   scrollBar   当前滚动条对象（this对象）
         * @body    console.log("top:"+_top+",_left:"+_left);
         * @description      上拉滚动条触底||触右时触发
         */
        _this.$emit('scrolltolower', _this.top, _this.left, _this)
        _this.loading = null
      }, this.delay)
    },
    // 垂直移动内容
    verticalMoveContent (nextPosition) {
      // 最大值
      const _maxValue = this.scrollAreaHeight - this.scrollWrapperHeight
      // Update the Vertical Value
      let top = nextPosition > _maxValue ? _maxValue : (nextPosition < 0 ? 0 : nextPosition)
      this.top = top > 0 ? top : 0
      // 有垂直滚动条
      if (this.hasVerticalScrollBar) {
        if (this.top == 0) {
          // 刷新
          this.scrolltoupper()
        }
        if (this.top == _maxValue) {
          // 加载
          this.scrolltolower()
        }
      }
    },
    // 水平移动内容
    horizontalMoveContent (nextPosition) {
      // Horizontal Scrolling
      const _maxValue = this.scrollAreaWidth - this.scrollWrapperWidth
      // Update the Horizontal Value
      this.left = nextPosition > _maxValue ? _maxValue : (nextPosition < 0 ? 0 : nextPosition)

      //  有水平滚动条
      if (this.hasHorizontalScrollBar) {
        if (this.left == 0) {
          // 刷新
          this.scrolltoupper()
        }
        if (this.left == _maxValue) {
          // 加载
          this.scrolltolower()
        }
      }
    },
    //  移动滚动条
    moveTheScrollbar () {
      // 垂直滚动条的位置
      this.verticalScrollBarPostion = this.top / this.scrollAreaHeight * 100
      // 水平滚动条的位置
      this.horizontalScrollBarPostion = this.left / this.scrollAreaWidth * 100
    },
    //  滚动条位置改变，触发父级事件
    handleChangePosition (scrollBarPostion, orientation, dragging) {
      this.dragging = dragging
      // Convert Percentage to Pixel
      let nextPosition = scrollBarPostion * 1.0 / 100 * (orientation == 'vertical' ? this.scrollAreaHeight : this.scrollAreaWidth)
      if (isNaN(nextPosition)) {
        return
      }
      nextPosition = parseInt(nextPosition)
      if (orientation == 'vertical') {
        this.verticalScrollBarPostion = scrollBarPostion
        this.verticalMoveContent(nextPosition)
      }
      if (orientation == 'horizontal') {
        this.horizontalScrollBarPostion = scrollBarPostion
        this.horizontalMoveContent(nextPosition)
      }
    },
    /**
     * @description 使用方法是因为  改变属性值第一次生效后，若滚动条用滚轮滚动后，第二次使用同样的属性值无法生效。
     *
     */
    updateTop (top, callback) {
      this.update(top, this.left, callback)
    },
    updateLeft (left, callback) {
      this.update(this.top, left, callback)
    },
    update (top, left, callback) {
      // 需要等数据加载完后
      this.$nextTick(function () {
        this.isUpdate = true
        // 计算大小
        this.calculateSize()
        // 获取top值
        const _top = typeof top === 'number' ? top : this.top
        const _left = typeof left === 'number' ? left : this.left
        // 垂直滚动条
        this.verticalMoveContent(_top)
        // 水平滚动条
        this.horizontalMoveContent(_left)
        //  移动滚动条
        this.moveTheScrollbar()
        // 执行回调函数
        if (typeof callback === 'function') {
          callback(this.top, this.left)
        }
      })
    },
    getStyle (prop) {
      return parseFloat(Artery.getStyle(this.$el, prop))
    },

    // 计算大小
    calculateSize () {
      // Scroll Wrapper Height and Width
      /*
       * let borderLeftAndRight = getStyle("border-left") + getStyle("border-right");
       *let paddingLeftAndRight = getStyle("border-left") + getStyle("border-right");
       */
      /*
       * this.scrollWrapperWidth = this.getStyle("width");
       *this.scrollWrapperHeight = this.getStyle("height");
       */
      const paddingLeftAndRight = this.getStyle('padding-left') + this.getStyle('padding-right')
      this.scrollWrapperWidth = this.$el.clientWidth - paddingLeftAndRight
      const paddingTopAndBottom = this.getStyle('padding-top') + this.getStyle('padding-bottom')
      this.scrollWrapperHeight = this.$el.clientHeight - paddingTopAndBottom
      // 获取第一个子节点
      const _firstChild = this.$refs.scrollArea.children[0]
      if (_firstChild && _firstChild.offsetWidth > this.scrollWrapperWidth) {
        this.$refs.scrollArea.style.width = _firstChild.offsetWidth + 'px'
      } else {
        this.$refs.scrollArea.style.width = '100%'
      }

      this.scrollAreaWidth = this.$refs.scrollArea.offsetWidth
      this.scrollAreaHeight = this.$refs.scrollArea.offsetHeight
      /*
       * adjust has or  has not  scroll bar
       * vertical  scroll bar
       */
      this.hasVerticalScrollBar = this.scrollAreaHeight > this.scrollWrapperHeight
      // horizontal  scroll bar
      this.hasHorizontalScrollBar = this.scrollAreaWidth > this.scrollWrapperWidth
      // Make sure The wrapper is Ready, then render the scrollbar
      this.ready = true
    }
  },
  updated () {
  },
  created () {
  },
  mounted () {
    //  default  calculate  size
    if (!this.inited) {
      this.calculateSize()
      // Attach The Event for Responsive View~
      const handler = () => {
        this.update(this.top, this.left)
      }

      addResizeListener(this.$refs.scrollArea, handler)
      addResizeListener(this.$refs.scrollWrapper, handler)
      /**
       * #event
       *
       * @name    ready
       * @param   scrollBar   当前滚动条对象（this对象）
       * @body    console.log("滚动条组件加载完成！");
       * @description     滚动条组件加载完成触发
       */
      this.$emit('ready', this)
      this.inited = true
    }

    // Artery.on(this.$refs.scrollArea, 'resize',);
  },
  beforeDestroy () {
    const handler = () => {
      this.update(this.top, this.left)
    }
    removeResizeListener(this.$refs.scrollArea, handler)
    removeResizeListener(this.$refs.scrollWrapper, handler)
    /*
     * Remove Event
     * Artery.off(this.$refs.scrollArea, 'resize', this.calculateSize);
     */
    /**
     * #event
     *
     * @name    destory
     * @param   scrollBar   当前滚动条对象（this对象）
     * @body    console.log("滚动条销毁！");
     * @description     滚动条组件销毁前触发
     */
    this.$emit('destory', this)
  }
}
export default module
